home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2004 #2 / K-CD-2-2004.ISO / OpenOffice Sv / f_0397 / python-core-2.2.2 / lib / mimetools.py < prev    next >
Encoding:
Python Source  |  2003-07-18  |  6.3 KB  |  227 lines

  1. """Various tools used by MIME-reading or MIME-writing programs."""
  2.  
  3.  
  4. import os
  5. import rfc822
  6. import tempfile
  7.  
  8. __all__ = ["Message","choose_boundary","encode","decode","copyliteral",
  9.            "copybinary"]
  10.  
  11. class Message(rfc822.Message):
  12.     """A derived class of rfc822.Message that knows about MIME headers and
  13.     contains some hooks for decoding encoded and multipart messages."""
  14.  
  15.     def __init__(self, fp, seekable = 1):
  16.         rfc822.Message.__init__(self, fp, seekable)
  17.         self.encodingheader = \
  18.                 self.getheader('content-transfer-encoding')
  19.         self.typeheader = \
  20.                 self.getheader('content-type')
  21.         self.parsetype()
  22.         self.parseplist()
  23.  
  24.     def parsetype(self):
  25.         str = self.typeheader
  26.         if str is None:
  27.             str = 'text/plain'
  28.         if ';' in str:
  29.             i = str.index(';')
  30.             self.plisttext = str[i:]
  31.             str = str[:i]
  32.         else:
  33.             self.plisttext = ''
  34.         fields = str.split('/')
  35.         for i in range(len(fields)):
  36.             fields[i] = fields[i].strip().lower()
  37.         self.type = '/'.join(fields)
  38.         self.maintype = fields[0]
  39.         self.subtype = '/'.join(fields[1:])
  40.  
  41.     def parseplist(self):
  42.         str = self.plisttext
  43.         self.plist = []
  44.         while str[:1] == ';':
  45.             str = str[1:]
  46.             if ';' in str:
  47.                 # XXX Should parse quotes!
  48.                 end = str.index(';')
  49.             else:
  50.                 end = len(str)
  51.             f = str[:end]
  52.             if '=' in f:
  53.                 i = f.index('=')
  54.                 f = f[:i].strip().lower() + \
  55.                         '=' + f[i+1:].strip()
  56.             self.plist.append(f.strip())
  57.             str = str[end:]
  58.  
  59.     def getplist(self):
  60.         return self.plist
  61.  
  62.     def getparam(self, name):
  63.         name = name.lower() + '='
  64.         n = len(name)
  65.         for p in self.plist:
  66.             if p[:n] == name:
  67.                 return rfc822.unquote(p[n:])
  68.         return None
  69.  
  70.     def getparamnames(self):
  71.         result = []
  72.         for p in self.plist:
  73.             i = p.find('=')
  74.             if i >= 0:
  75.                 result.append(p[:i].lower())
  76.         return result
  77.  
  78.     def getencoding(self):
  79.         if self.encodingheader is None:
  80.             return '7bit'
  81.         return self.encodingheader.lower()
  82.  
  83.     def gettype(self):
  84.         return self.type
  85.  
  86.     def getmaintype(self):
  87.         return self.maintype
  88.  
  89.     def getsubtype(self):
  90.         return self.subtype
  91.  
  92.  
  93.  
  94.  
  95. # Utility functions
  96. # -----------------
  97.  
  98.  
  99. _prefix = None
  100.  
  101. def choose_boundary():
  102.     """Return a random string usable as a multipart boundary.
  103.     The method used is so that it is *very* unlikely that the same
  104.     string of characters will every occur again in the Universe,
  105.     so the caller needn't check the data it is packing for the
  106.     occurrence of the boundary.
  107.  
  108.     The boundary contains dots so you have to quote it in the header."""
  109.  
  110.     global _prefix
  111.     import time
  112.     import random
  113.     if _prefix is None:
  114.         import socket
  115.         import os
  116.         hostid = socket.gethostbyname(socket.gethostname())
  117.         try:
  118.             uid = `os.getuid()`
  119.         except:
  120.             uid = '1'
  121.         try:
  122.             pid = `os.getpid()`
  123.         except:
  124.             pid = '1'
  125.         _prefix = hostid + '.' + uid + '.' + pid
  126.     timestamp = '%.3f' % time.time()
  127.     seed = `random.randint(0, 32767)`
  128.     return _prefix + '.' + timestamp + '.' + seed
  129.  
  130.  
  131. # Subroutines for decoding some common content-transfer-types
  132.  
  133. def decode(input, output, encoding):
  134.     """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
  135.     if encoding == 'base64':
  136.         import base64
  137.         return base64.decode(input, output)
  138.     if encoding == 'quoted-printable':
  139.         import quopri
  140.         return quopri.decode(input, output)
  141.     if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
  142.         import uu
  143.         return uu.decode(input, output)
  144.     if encoding in ('7bit', '8bit'):
  145.         return output.write(input.read())
  146.     if decodetab.has_key(encoding):
  147.         pipethrough(input, decodetab[encoding], output)
  148.     else:
  149.         raise ValueError, \
  150.               'unknown Content-Transfer-Encoding: %s' % encoding
  151.  
  152. def encode(input, output, encoding):
  153.     """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
  154.     if encoding == 'base64':
  155.         import base64
  156.         return base64.encode(input, output)
  157.     if encoding == 'quoted-printable':
  158.         import quopri
  159.         return quopri.encode(input, output, 0)
  160.     if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
  161.         import uu
  162.         return uu.encode(input, output)
  163.     if encoding in ('7bit', '8bit'):
  164.         return output.write(input.read())
  165.     if encodetab.has_key(encoding):
  166.         pipethrough(input, encodetab[encoding], output)
  167.     else:
  168.         raise ValueError, \
  169.               'unknown Content-Transfer-Encoding: %s' % encoding
  170.  
  171. # The following is no longer used for standard encodings
  172.  
  173. # XXX This requires that uudecode and mmencode are in $PATH
  174.  
  175. uudecode_pipe = '''(
  176. TEMP=/tmp/@uu.$$
  177. sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
  178. cat $TEMP
  179. rm $TEMP
  180. )'''
  181.  
  182. decodetab = {
  183.         'uuencode':             uudecode_pipe,
  184.         'x-uuencode':           uudecode_pipe,
  185.         'uue':                  uudecode_pipe,
  186.         'x-uue':                uudecode_pipe,
  187.         'quoted-printable':     'mmencode -u -q',
  188.         'base64':               'mmencode -u -b',
  189. }
  190.  
  191. encodetab = {
  192.         'x-uuencode':           'uuencode tempfile',
  193.         'uuencode':             'uuencode tempfile',
  194.         'x-uue':                'uuencode tempfile',
  195.         'uue':                  'uuencode tempfile',
  196.         'quoted-printable':     'mmencode -q',
  197.         'base64':               'mmencode -b',
  198. }
  199.  
  200. def pipeto(input, command):
  201.     pipe = os.popen(command, 'w')
  202.     copyliteral(input, pipe)
  203.     pipe.close()
  204.  
  205. def pipethrough(input, command, output):
  206.     tempname = tempfile.mktemp()
  207.     temp = open(tempname, 'w')
  208.     copyliteral(input, temp)
  209.     temp.close()
  210.     pipe = os.popen(command + ' <' + tempname, 'r')
  211.     copybinary(pipe, output)
  212.     pipe.close()
  213.     os.unlink(tempname)
  214.  
  215. def copyliteral(input, output):
  216.     while 1:
  217.         line = input.readline()
  218.         if not line: break
  219.         output.write(line)
  220.  
  221. def copybinary(input, output):
  222.     BUFSIZE = 8192
  223.     while 1:
  224.         line = input.read(BUFSIZE)
  225.         if not line: break
  226.         output.write(line)
  227.